/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.javanile.chess.stone;

/**
 *
 * @author totalinnovation
 */
public class Game {
    private boolean DEBUG = false;
    public void	setDebug(boolean x) {DEBUG=x;}
    
    private Board   b;
    private Moves   m;
    private Console c;

    public Game(Console console) {
	c = console;
	b = new Board();
	m = new Moves(300);
    }

    public Game(Console console, String fen) {
	c = console;
	b = new Board(fen);
	m = new Moves(300);
    }
    
    public int eat(String cmd) {
	eat_move(cmd);
	return 0;
    }
    
    public void eat_move(String move) {
	int[] mv = Less.move(move);
	domove(mv[Stone.from],mv[Stone.to]);
    }

    public List moves() {
	List ms = new List();
	for(int s=0;s<Stone.BOARD_SIZE;s++) {
	    if (b.turn() * b.get(s) > 0) {		
	    	Piece p = b.piece(s);
		if (DEBUG) {c.put(Less.piece(p)+" "+Less.square(s));}
		for(int d=0;d<p.directions();d++) {
		    switch(p.direction(d)){
			// mossa con obbligo di cattura
			case Stone.c:
			    for(int i=0;i<p.squares(s,d);i++) {
				if (b.get(s) * b.get(p.square(s,d,i)) < 0) ms.add(s, p.square(s,d,i));
			    }break;
			// mossa libera fino ad ostacolo o cattura
			case Stone.sc:
			    for(int i=0;i<p.squares(s,d);i++) {
				if(b.get(s) * b.get(p.square(s,d,i)) == 0) {
				    ms.add(s, p.square(s,d,i));
				} else if (b.get(s) * b.get(p.square(s,d,i)) < 0) {
				    ms.add(s, p.square(s,d,i));break;
				} else break;
			    }break;
			// mossa libera fino ad ostacolo
			case Stone.s:
			    for(int i=0;i<p.squares(s,d);i++) {
				if(b.get(s) * b.get(p.square(s,d,i)) == 0) ms.add(s, p.square(s,d,i)); else break;
			    }break;
			// mossa senza ostacoli cattura o salto
			case Stone.hc:
			    for(int i=0;i<p.squares(s,d);i++) {
				if(b.get(s) * b.get(p.square(s,d,i)) <= 0) ms.add(s, p.square(s,d,i));
			    }break;
		    }
		}
	    }
	}
	return ms;
    }

    public void domove(int[] m) {
	domove((byte)m[0],(byte)m[1]);
    }

    public void domove(int from, int to) {
	domove((byte)from,(byte)to);
    }

    public void domove(byte from, byte to) {
	m.move(from, to, (byte)b.get(from), (byte)b.get(to));
	b.move(from, to);
	b.swap();
    }

    public void unmove() {
	m.undo();
	b.set(m.move().from(), m.move().moved());
	b.set(m.move().to(),   m.move().captured());
	b.swap();
    }

    public int evalmove(int[] mv) {
	//if (DEBUG) c.put(" * "+Less.move(mv)+" "+b.turn());
	domove(mv);
	int p = -b.turn() * eval0();
	unmove();
	return p;
    }

    public int eval0() {
	int eval = 0;
	for(int s=0;s<64;s++) {
	    int p = Math.abs(b.get(s))-1;
	    if (p>=0) {
		eval = eval + (int)Math.signum(b.get(s)) * Stone.val[p];
		eval = eval + ((int)Math.signum(b.get(s))*(1000-Stone.val[p])*Stone.boardval[s])/1000;
	    }
	}
	return eval;
    }
    
    public int losemove(int[] m) {
	domove(m);
	List mr = moves();
	int max = -10000;
	while(mr.next()) {
	    int p = evalmove(mr.move());
	    if (p>max) max = p;
	}
	unmove();
	return max;
    }

    public int[] mainmove() {
	List ms = this.moves();
	int[] mainmove = new int[5];
	int min = +10000;
	while(ms.next()) {
	    int max = this.losemove(ms.move());
	    if (max<min) {
		min = max;
		mainmove = ms.move();
	    }
	}
	return mainmove;
    }

    //
    public void domoves(int[][] moves, int level) {
	for(int i=0;i<level;i++) {
	    this.domove(moves[i]);
	}
    }

    public void unmoves(int level) {
	for(int i=0;i<level;i++) {
	    this.unmove();
	}
    }

    public int[] dump() {
	return b.dump();
    }
}